"""
测试配置和工具
"""
import asyncio
import pytest
import pytest_asyncio
from typing import AsyncGenerator, Generator
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
from sqlalchemy.pool import StaticPool
from fastapi.testclient import TestClient

from app.main import app
from app.core.database import Base, get_db
from app.core.config import settings

# 测试数据库URL (使用SQLite内存数据库)
TEST_DATABASE_URL = "sqlite+aiosqlite:///:memory:"

# 创建测试引擎
test_engine = create_async_engine(
    TEST_DATABASE_URL,
    poolclass=StaticPool,
    connect_args={"check_same_thread": False}
)

# 创建测试会话工厂
TestSessionLocal = async_sessionmaker(
    test_engine,
    class_=AsyncSession,
    expire_on_commit=False,
    autocommit=False,
    autoflush=False,
)


@pytest_asyncio.fixture(scope="session")
def event_loop() -> Generator:
    """创建事件循环"""
    loop = asyncio.get_event_loop_policy().new_event_loop()
    yield loop
    loop.close()


@pytest_asyncio.fixture(scope="session")
async def init_test_db():
    """初始化测试数据库"""
    async with test_engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    yield
    async with test_engine.begin() as conn:
        await conn.run_sync(Base.metadata.drop_all)


@pytest_asyncio.fixture
async def db_session(init_test_db) -> AsyncGenerator[AsyncSession, None]:
    """创建数据库会话"""
    async with TestSessionLocal() as session:
        yield session
        await session.rollback()


@pytest.fixture
def client(db_session: AsyncSession) -> Generator:
    """创建测试客户端"""
    def get_test_db():
        try:
            yield db_session
        finally:
            pass
    
    app.dependency_overrides[get_db] = get_test_db
    with TestClient(app) as test_client:
        yield test_client
    app.dependency_overrides.clear()


@pytest.fixture
def test_settings():
    """测试配置"""
    return settings


# 测试数据工厂
class TestDataFactory:
    """测试数据工厂"""
    
    @staticmethod
    def user_data(**kwargs):
        """用户测试数据"""
        default_data = {
            "username": "testuser",
            "email": "test@example.com",
            "password": "testpassword123",
            "full_name": "Test User",
            "organization": "Test Org"
        }
        default_data.update(kwargs)
        return default_data
    
    @staticmethod
    def project_data(**kwargs):
        """项目测试数据"""
        default_data = {
            "name": "测试项目",
            "description": "这是一个测试项目",
            "scenario_type": "smart_lighting",
            "config": {"test": True},
            "tags": ["测试"],
            "is_public": True
        }
        default_data.update(kwargs)
        return default_data
    
    @staticmethod
    def data_source_data(**kwargs):
        """数据源测试数据"""
        default_data = {
            "name": "测试数据源",
            "description": "测试用数据源",
            "source_type": "mqtt",
            "data_format": "json",
            "connection_config": {
                "host": "test.mqtt.com",
                "port": 1883,
                "topic": "test/topic"
            },
            "data_schema": {
                "temperature": {"type": "float"},
                "humidity": {"type": "float"}
            }
        }
        default_data.update(kwargs)
        return default_data
    
    @staticmethod
    def training_job_data(**kwargs):
        """训练任务测试数据"""
        default_data = {
            "name": "测试训练任务",
            "description": "测试用训练任务",
            "training_type": "supervised",
            "model_architecture": "transformer",
            "total_epochs": 10,
            "hyperparameters": {
                "learning_rate": 0.001,
                "batch_size": 32
            },
            "training_config": {
                "optimizer": "adam",
                "loss_function": "mse"
            },
            "resource_requirements": {
                "gpu_count": 1,
                "memory_gb": 8
            },
            "dataset_config": {
                "features": ["temperature", "humidity"],
                "target": "brightness"
            },
            "data_split_config": {
                "train_ratio": 0.7,
                "val_ratio": 0.2,
                "test_ratio": 0.1
            }
        }
        default_data.update(kwargs)
        return default_data
    
    @staticmethod
    def model_data(**kwargs):
        """模型测试数据"""
        default_data = {
            "name": "测试模型",
            "version": "v1.0.0",
            "description": "测试用模型",
            "model_type": "transformer",
            "model_format": "pytorch",
            "model_config": {
                "hidden_size": 512,
                "num_layers": 6
            },
            "input_schema": {
                "features": ["temperature", "humidity"]
            },
            "output_schema": {
                "brightness": {"type": "float"}
            },
            "model_tags": ["测试"]
        }
        default_data.update(kwargs)
        return default_data


# 创建全局测试数据工厂实例
test_data = TestDataFactory()


# 辅助函数
async def create_test_user(db: AsyncSession, **kwargs):
    """创建测试用户"""
    from app.models.user import User
    from app.core.security import get_password_hash
    
    user_data = test_data.user_data(**kwargs)
    password = user_data.pop("password")
    user_data["password_hash"] = get_password_hash(password)
    
    user = User(**user_data)
    db.add(user)
    await db.commit()
    await db.refresh(user)
    return user


async def create_test_project(db: AsyncSession, owner_id: int, **kwargs):
    """创建测试项目"""
    from app.models.project import Project
    
    project_data = test_data.project_data(**kwargs)
    project_data["owner_id"] = owner_id
    
    project = Project(**project_data)
    db.add(project)
    await db.commit()
    await db.refresh(project)
    return project